import csv
import math
from BD import TransBD, BD_2D_LEVELS_SIZE


# 通用函数
def lon_normalize(lon):
    lon2 = ((lon + 180.0) % 360.0) - 180.0
    if abs(lon2 + 180.0) < 1e-12:
        return 180.0
    return lon2


def lon_in_grid(lon, lon_min, lon_max, tol=1e-12):
    """判断经度是否在区间内（考虑跨180°）"""
    lon = lon_normalize(lon)
    lon_min = lon_normalize(lon_min)
    lon_max = lon_normalize(lon_max)
    if lon_min < lon_max:
        return (lon_min - tol) <= lon < (lon_max + tol)
    else:
        return (lon >= lon_min - tol and lon <= 180 + tol) or (lon >= -180 - tol and lon < lon_max + tol)


# 边界点生成
def generate_boundary_points(level, size_lon, size_lat):
    """仅生成每级格网的边界交点（角点）"""
    pts = []
    n_lon = int(round(360.0 / size_lon))
    n_lat = int(round(168.0 / size_lat))
    step = max(1, n_lon // 12)
    for i in range(0, n_lat + 1, step):
        for j in range(0, n_lon + 1, step):
            lon = -180 + j * size_lon
            lat = -84 + i * size_lat
            pts.append({'lat': lat, 'lon': lon})
    return pts


# 单级验证
def validate_level(level, trans_bd):
    level_name = f"Level_2D_{level}"
    size_lon, size_lat = getattr(BD_2D_LEVELS_SIZE, level_name).value
    tol = max(1e-12, min(size_lon, size_lat) * 1e-5)

    points = generate_boundary_points(level, size_lon, size_lat)
    rows = []
    total = len(points)
    success_geo = 0
    success_code = 0
    success_combined = 0

    for idx, pt in enumerate(points, 1):
        lat, lon = pt['lat'], pt['lon']
        row = {
            "编号": idx,
            "级别": level,
            "类型": "边界点",
            "坐标": f"({lat:.9f}, {lon:.9f})",
            "描述": f"{level}级网格边界点",
            "网格码": "",
            "角点": "",
            "范围": "",
            "是否在格内": "否",
            "格号一致": "否",
            "验证结果": "失败",
            "详情": ""
        }

        try:
            # 正向转换：坐标 → 网格码
            code = trans_bd.coordinates_to_bd2d_level(lat, lon, level)
            row["网格码"] = code

            # === 一级网格特判 ===
            if level == 1:
                lat_min = math.floor(lat / size_lat) * size_lat
                lon_min = math.floor(lon / size_lon) * size_lon
                lat_max = lat_min + size_lat
                lon_max = lon_min + size_lon
            else:
                # 高级别：按中心点 ±½格
                lat_center, lon_center = trans_bd.bd2d_to_coordinates_level(code, level)
                lat_min = lat_center - size_lat / 2
                lon_min = lon_center - size_lon / 2
                lat_max = lat_center + size_lat / 2
                lon_max = lon_center + size_lon / 2

            # 几何验证：判断该边界点是否在格子范围内
            in_lat = (lat_min - tol) <= lat <= (lat_max + tol)
            in_lon = lon_in_grid(lon, lon_min, lon_max, tol)
            geo_success = in_lat and in_lon
            if geo_success:
                success_geo += 1

            # 格号一致性验证：用角点再编码
            code_back = trans_bd.coordinates_to_bd2d_level(lat, lon, level)
            code_match = (code == code_back)
            if code_match:
                success_code += 1

            # 综合判断
            if geo_success or code_match:
                success_combined += 1
                row["验证结果"] = "成功"
                row["是否在格内"] = "是"
                if code_match:
                    row["格号一致"] = "是"

            # 输出网格信息
            row["角点"] = f"({lat_min:.9f}, {lon_min:.9f})"
            row["范围"] = f"纬度[{lat_min:.9f} ~ {lat_max:.9f}], 经度[{lon_min:.9f} ~ {lon_max:.9f}]"

            # 中文详情输出
            row["详情"] = (
                f"几何验证：{'通过' if geo_success else '未通过'}；"
                f"格号一致：{'是' if code_match else '否'}；"
                f"容差={tol:.1e}"
            )

        except Exception as e:
            row["验证结果"] = "异常"
            row["详情"] = f"计算异常：{str(e)}"

        rows.append(row)

    return rows, total, success_geo, success_code, success_combined


# 主流程
def validate_all_levels():
    trans = TransBD()
    summary = []

    for lvl in range(1, 11):
        print(f"\n▶ 正在验证第 {lvl} 级网格（仅边界点）...")
        rows, total, succ_geo, succ_code, succ_comb = validate_level(lvl, trans)

        # 写入 CSV
        fname = f"grid_level{lvl}_boundary_validation.csv"
        failname = f"grid_level{lvl}_boundary_failed.csv"
        fields = ["编号", "级别", "类型", "坐标", "描述", "网格码",
                  "角点", "范围", "是否在格内", "格号一致", "验证结果", "详情"]

        with open(fname, "w", newline="", encoding="utf-8-sig") as f:
            writer = csv.DictWriter(f, fieldnames=fields)
            writer.writeheader()
            writer.writerows(rows)

        fails = [r for r in rows if r["验证结果"] != "成功"]
        if fails:
            with open(failname, "w", newline="", encoding="utf-8-sig") as f:
                writer = csv.DictWriter(f, fieldnames=fields)
                writer.writeheader()
                writer.writerows(fails)

        rate_geo = succ_geo / total * 100
        rate_code = succ_code / total * 100
        rate_comb = succ_comb / total * 100
        summary.append((lvl, total, rate_geo, rate_code, rate_comb))

        print(f"  成功率（几何）：{rate_geo:.2f}%  格号一致：{rate_code:.2f}%  综合：{rate_comb:.2f}%")

    # 汇总结果
    print("\n" + "=" * 80)
    print("逐级网格边界验证汇总")
    print("=" * 80)
    total_all = sum(t for _, t, _, _, _ in summary)
    succ_all = sum(int(t * rc / 100) for _, t, _, _, rc in summary)
    for lvl, total, rg, rc, rcomb in summary:
        print(f"第 {lvl:2d} 级网格：综合成功率 {rcomb:6.2f}%（几何：{rg:.2f}%，格号：{rc:.2f}%）")
    print("-" * 60)
    print(f"总体综合成功率 ≈ {(succ_all / total_all) * 100:.2f}%")
    print("=" * 80)


if __name__ == "__main__":
    validate_all_levels()
